<?php

/**
 * @todo 1. field specific filters / modifiers
 * 2. checkboxes for bulk actions
 * 3. AJAX based sorting / pagination
 * 4. Specify no. of rows to be shown in textbox
 */ 

class IndexHelper extends AppHelper 
{
	var $helpers = array('Html', 'Paginator', 'Javascript', 'Form');
	var $actions = array();
	var $pagination = true;
	var $paginateCounter = 'Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%';
	var $displayFields = array();
	var $sortableFields = array();
	var $customFields = array();
	//var $rowSelector = true;
	var $buttons = array();
	
	var $_data = false;
	
	var $modelObj = false;
	
	var $limitCheckbox = true;
	
	var $paginateSeperator = ' | '; 

	var $customFuncParamCount = array();  // to cache number of arguments of custom functions
	
	function setData($data, $modelName)
	{
		$this->_data = $data;
		if(is_object($modelName))
		{
			$this->modelObj = $modelName;
		}
		else
		{
			parent::setEntity($modelName);
		}
		
		if(!isset(ClassRegistry::getObject('view')->params['paging']))
			$this->pagination = false;
	}
	
	function model()
	{
		if(is_object($this->modelObj))
		{
			return $this->modelObj->alias;
		}
		return parent::model();
	}
	
	function getModelObj($alias = false)
	{

		if(!$alias)
		{
			if(is_object($this->modelObj))
			{
				return $this->modelObj;
			}
			return ClassRegistry::getObject($this->model());
		}
		else
		{
			if(is_object($this->modelObj) && $this->modelObj->alias == $alias)
			{
				return $this->modelObj;
			}
			return ClassRegistry::getObject($alias);			
		}
			
	}
	
	/**
	 * Displays table from array 
	 * $data array should be in such format:
	 * [0] =>
	 * 		[Jerk] =>
	 * 			[name] => Manu
	 * 			[address] => Giga
	 * [1] =>
	 * 		[Jerk] =>
	 * 			[name] => Shriti
	 * 			[address] => giga2
	 */
	function display($options = array())
	{
		if(empty($this->_data))
		{
			return "<h4>".__("No records found!")."</h4>";
		}
		if(isset($options['id']))
		{
			$this->elementId = $options['id'];
		}
		else
		{
			$this->elementId = 'table_'.mt_rand();
		}
		
		if(!isset($options['class']))
		{
			$options['class'] = null;
		}	
		
		$records = $this->_data;
		$this->output = null;	
		
		//code add limit filter
		if($this->limitCheckbox)
		{
			$this->output .= $this->getLimitCheckbox();
		}
		
		
		if(!empty($this->customFields))
		{
			$records = $this->_mergeCustomFields($records);
		}
		
		if($this->pagination && $this->paginateCounter)
		{
			$this->_buildPaginationCounter();
		}
		
		$fields = array_keys($records[0][$this->model()]);
		$this->_models[$this->model()] = $this->getModelObj();
		if(empty($this->displayFields))
		{
			$this->displayFields = $fields;
		}

		$this->_buildHeader($options);
		$this->_buildRows($records, $options);
		$this->_buildFooter($options);
		
		$this->_buildBulkActions($options);
		
		if($this->pagination)
		{
			$view = ClassRegistry :: getObject('view');
			$this->Paginator->options(array('url' => $view->passedArgs)); // hack to make right urls
			$this->_buildPagination();
		}
		
		$this->Javascript->startup("$('.tabeSelectors').attr('checked', false);");  // output it only once
		
		$this->_clear();
		return $this->output;
	}
	
	function getLimitCheckbox()
	{
		$output = "";
		//@FIXME;
		$url = Router::url(am(array_diff_key($this->params['named'],array('limit'=>'')),$this->params['pass']));
		$url = "'".$url."'";
		$output =
		'<div class="input select page_limit"><label>'.__("Show per page").'</label> <select name="data[filter]" onchange="showRecords(this,'.$url.');" id="limit_filter">
		<option value="">'.__("-Select-").'</option>
		<option value="10" selected="selected">10</option>
		<option value="25">25</option>
		<option value="50">50</option>		
		<option value="100">100</option>
		<option value="500">500</option>		
		</select></div><div class="clear"></div>';
		return $output;
	}
	
	function _buildHeader($options = array())
	{
		$this->output .= '<table id="'.$this->elementId.'" cellspacing="0" border="0" class="index table '.$options['class'].'">';
		$this->output .= '<tr class="headerrow">';
		
		if(!empty($this->buttons))
		{
			$this->output .= '<th><input value="" class="tabeSelectors" type="checkbox" onchange="$(\'#'.$this->elementId.' .tabeSelectors\').attr(\'checked\',$(this).attr(\'checked\') == \'checked\' )"></th>';
		}
		foreach($this->displayFields as $field)
		{
			$fieldInfo = $this->_getFieldInfo($field);
			extract($fieldInfo);
			$label = __($label);
			$heading = $label;
			
			if(in_array($model.'.'.$field, $this->sortableFields))  // if sortable
			{
				$heading = $this->Paginator->sort($label, $model.'.'.$field);
			}	
			$this->output .= "<th>".$heading."</th>";
		}
		if(!empty($this->actions))
		{
			$this->output .= "<th>".__("Actions")."</th>";
		}
		$this->output .= "</tr>";
	}
	
	function _buildFooter($options)
	{
		$this->output .= "</table>";
	}
	
	function _buildRows($records, $options = array())
	{
		$i = 0;
		foreach($records as $record)
		{
			$class = "inforow";
			if ($i++ % 2 == 0) {
				$class .= ' altrow"';
			}
			$rowId = $this->model().'Row_'.$record[$this->model()]['id'];
			$this->output .= "<tr class=\"$class\" id=\"$rowId\">";
			
			if(!empty($this->buttons))
			{
				$this->output .= '<td><input value="'.$record[$this->model()]['id'].'" class="tabeSelectors" type="checkbox" onchange=\'$(this).parent().parent().toggleClass("selected");\'></td>'; // @todo finish checkbox / row selector
			}
			foreach($this->displayFields as $field)
			{
				$fieldInfo = $this->_getFieldInfo($field);
				extract($fieldInfo);
				if(isset($record[$model]))
				{
					if(!isset($this->_models[$model]))
					{
						$this->_models[$model] = $this->getModelObj($model);
					}
					$value = $this->_models[$model]->showValue($field, $record[$model]);
				}
				else
				{
					$value = __("N/A");
				}
				$this->output .= "<td>".$value."</td>";
			}
			$model = $this->model(); // reset to main model
			
			// check if any action is set
			if(!empty($this->actions))
			{
				$this->output .= '<td class="actions">';
				foreach($this->actions as $action)
				{
					//prd($record);
					extract($action);
					$tmpRecord = Utility::dotNotation($record);
					$title = String::insert($title, $tmpRecord);
					$url = String::insert($url, $tmpRecord);
					$confirmMessage = String::insert($confirmMessage, $tmpRecord);
					
					$showLink = true;
					if($filterFunction)
					{
						$filterResponse = $filterFunction($model, $record);

						if($filterResponse)
						{
							if(is_array($filterResponse))
							{
								extract($filterResponse);
							}
						}
						else
						{
							$showLink = false;
						}
					}
					if($showLink)
						$this->output .= $this->Html->link($title, $url, $htmlAttributes, $confirmMessage, $escapeTitle);
				}
				$this->output .= "</td>";
			}
		}
		$this->output .= "</tr>";
	}
	
	function _buildPagination()
	{
		$this->output .= '<div class="paging paginate">';
		$this->output .=  $this->Paginator->prev('<< '.__('previous', true), array(), null, array('class'=>'disabled')).'';
		$this->output .=  $this->Paginator->numbers(array('separator'=>$this->getPaginateSeparator()))." ";
		$this->output .=  $this->Paginator->next(__('next', true).' >>', array(), null, array('class'=>'disabled'));
		$this->output .= '</div><div class="clear"></div>';
	}
	
	function showFields($fields)
	{
		$this->displayFields = $fields;
	}
	
	function sortableFields($fields)
	{
		foreach($fields as $key=>$field)
		{
			extract($this->_getFieldInfo($field));
			$fields[$key] = $model.'.'.$field;
		}
		$this->sortableFields = $fields;
	}
	
	function setAction($title, $url = null, $htmlAttributes = array(), $confirmMessage = false, $escapeTitle = true, $filterFunction = false)
	{
		$title = __($title);
		$newAction = compact('title',  'url', 'htmlAttributes', 'confirmMessage', 'escapeTitle', 'filterFunction');
		$this->actions[] = $newAction;
	}
	
	function _clear()
	{
		// reset to defaults
		$this->displayFields = array();
		$this->pagination = true;
		$this->actions = array();
	}
	
	function _buildPaginationCounter()
	{
		$this->output .= $this->Paginator->counter(array('format' => __($this->paginateCounter, true)));
	}
	
	/**
	 * Adds custom field to the table.
	 * Minimize the usage of this function - before using this ask yourself if field would be a better fit for model's additional field
	 */
	function addField($label, $func)
	{
		$newField = compact('label', 'func');
		$this->customFields[] = $newField;
	}
	
	function _mergeCustomFields($records)
	{
		foreach($records as $key => $record)
		{
			//$record = $record[$this->model()];
			foreach($this->customFields as $customField)
			{
				// little enhancement to send proper helper objects across custom field functions
				if(!isset($this->customFuncParamCount[$customField['func']]))
				{
					$fct = new ReflectionFunction($customField['func']);
					$argCount = $fct->getNumberOfRequiredParameters();
					$this->customFuncParamCount[$customField['func']] = $argCount;
				} else {
					$argCount = $this->customFuncParamCount[$customField['func']];
				}
				if($argCount == 1)
					$value = $customField['func']($record);
				if($argCount == 2)
					$value = $customField['func']($record, $this);

				 $record[$this->model()][$customField['label']] = $value;
			}
			$records[$key] = $record;
		}
		return $records;
	}
	
	function _getFieldInfo($field)
	{
		if(is_array($field))
		{
			$label = array_values($field);
			$label = $label[0];
			
			$field = array_keys($field);
			$field = $field[0];
		}
		$model = $this->model();
		if(strpos($field, '.'))
		{
			$tmp = explode('.', $field);
			$field = $tmp[1];
			$model = $tmp[0];
		}
		if(!isset($label))
		{
			$label = $field;
			$label = Inflector::humanize($label);
			if(isset($this->_models[$model]) &&  is_object($this->_models[$model]))
			{
				$label = $this->_models[$model]->getFieldProperties($field, 'label');
			}
		}
		
		$fieldInfo = compact('field', 'model', 'label');
		return $fieldInfo;
	}
	
	/**
	 * Footer buttons for bulk actions
	 */
	function addButton($title, $action, $options = array())
	{
		$this->buttons[] = compact('title', 'action', 'options');
	}
	
	function _buildBulkActions($options)
	{
		if(empty($this->buttons))
			return;
		//echo $this->model(); exit;
		$this->output .= "<div class='bulk_button'>";
		foreach($this->buttons as $key => $button)
		{
			extract($button);
			$defaultOptions = array();
			$defaultOptions['url'] = $action;
			$defaultOptions['class'] = 'inline';
			$defaultOptions['model'] = $this->model();
			$fieldDomId = Inflector::slug($title.'_action');
			//$fieldDomId = null;
			$defaultOptions['onSubmit'] = "if(!confirm('".__("Are you sure?")."')){return false;}";
			$defaultOptions['onSubmit'] .= '$(\'#'.$fieldDomId.'\').val(getSelectedRows(\''.$this->elementId.'\'));';
			//added this for showing confirmation before running delete or requested action 
			if(isset($options['onSubmit']))
			{
				$options['onSubmit'] = $options['onSubmit']." ".$defaultOptions['onSubmit'];
			}
			$options['escape'] = false;
			$options = am($defaultOptions, $options);
			$model = $options['model'];
			$this->output .= $this->Form->create($model, $options);
			$this->output .= $this->Form->input('ids', array('type'=>'hidden','id'=>$fieldDomId));
			$this->output .= $this->Form->input('plugin', array('type'=>'hidden','value'=>$this->plugin));
			$this->output .= $this->Form->end(__($title));
		}
		$this->output .= "</div>";
		//$this->output = $this->Html->button
	}
	
	function addColumn($name, $filterFunc)
	{
		$this->customFields[] = array('label'=>$name, 'func'=>$filterFunc);
	}
	
	function setPaginateSeparator($seperator = ' | ')
	{
		$this->paginateSeperator = $seperator;
	}
	
	function getPaginateSeparator()
	{
		return $this->paginateSeperator;
	}
	function afterRender()
	{
		if(isset($this->params['named']['limit']))
		{
			$limit = $this->params['named']['limit'];
			echo '<script>$("#limit_filter").val('.$limit.')</script>';
		}
		
	}
}
?>